package com.webull.information.center.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.webull.framework.mvc.ApiException;
import com.webull.information.center.common.util.MessageSender;
import com.webull.information.center.dao.InfoNewsDao;
import com.webull.information.center.dao.NewsAssociateDao;
import com.webull.information.center.validator.NewsValidator;
import com.webull.information.client.model.News;
import com.webull.information.client.model.NewsAssociate;
import com.webull.information.client.model.NewsLabel;
import com.webull.information.client.model.NewsLabelExt;
import com.webull.information.client.model.parm.NewsParam;
import com.webull.information.client.model.parm.NewsRelType;
import com.webull.information.client.model.parm.NewsUpdateEvent;
import com.webull.information.client.service.InfoNewsService;
import com.webull.securities.client.service.TickerService;

/**
 * @author shimingjun
 * @version 1.0
 * @date 2016年7月11日 下午6:36:24
 * @since JDK 1.8
 */

@Service
public class InfoNewsServiceImpl implements InfoNewsService {
    protected final Logger logger = LogManager.getLogger(getClass());
    private @Autowired
    NewsValidator newsValidator;
    private @Autowired
    InfoNewsDao infoNewsDao;
    private @Autowired
    MessageSender messageSender;
    private @Autowired
    TickerService tickerService;
    private @Autowired
    NewsAssociateDao newsAssociateDao;


    /**
     * 根据urlMd5判断该url是否存在2
     */
    @Override
    public News getByUrlMd5(String urlMd5) throws ApiException {
        newsValidator.validateStringError(urlMd5);
        News news = infoNewsDao.getByUrlMd5(urlMd5);
        return news;
    }

    @Override
	public News getBySumMd5(String sumMd5, NewsRelType type, Integer targetId, Date time) throws ApiException {
        newsValidator.validateStringError(sumMd5);
		// newsValidator.validateGetById(targetId);
        if (NewsRelType.currency.equals(type)) {
			return infoNewsDao.getBySumMd5_c(sumMd5, targetId, time);
        } else if (NewsRelType.futureCategory.equals(type)) {
			return infoNewsDao.getBySumMd5_f(sumMd5, targetId, time);
        } else if (NewsRelType.ticker.equals(type)) {
			return infoNewsDao.getBySumMd5(sumMd5, targetId, time);
		} else if (NewsRelType.homePage.equals(type)) {
			return infoNewsDao.getBySumMd5_h(sumMd5, time);
        }
        return null;
    }

    /**
     * 新增关联关系
     *
     * @param targetId
     * @param newsId
     * @throws ApiException
     * @since 0.1.0
     */
    @Override
    public void addNewsInfoRel(Integer targetId, NewsRelType type, Integer newsId) throws ApiException {
		if (!NewsRelType.homePage.equals(type)) {
			newsValidator.validateGetById(targetId);
		}
        newsValidator.validateGetById(newsId);
        int a = 0;
        NewsUpdateEvent event = NewsUpdateEvent.produceInstance(newsId.longValue());
        if (NewsRelType.currency.equals(type)) {
            a = infoNewsDao.addCurrencyNewsRel(targetId, newsId);
            event.setCurrencyId(targetId);
        } else if (NewsRelType.futureCategory.equals(type)) {
            a = infoNewsDao.addFutureCatNewsRel(targetId, newsId);
            event.setFutureGroupId(targetId);
        } else if (NewsRelType.ticker.equals(type)) {
            Integer tickerType = Optional.ofNullable(tickerService.getById(targetId))//
                    .map(v -> v.getTickerType()).orElse(null);
            a = infoNewsDao.addTickerNewsRel(targetId, newsId, tickerType);
            event.setTickerId(targetId);
        } else if (NewsRelType.associate.equals(type)) {
            NewsAssociate assoc = new NewsAssociate();
            assoc.setNewsId(targetId);
            assoc.setAssNewsId(newsId);

            event.setNewsId(Long.valueOf(targetId));
            event.setAssociateId(newsId);
            a = newsAssociateDao.addNewsAssociate(assoc);
        }

        if (a >= 1) {
            messageSender.sendModify(event);
            //
        }
    }

    @Override
    public Long bindNewsRecord(Integer targetId, NewsRelType type, News news) throws ApiException {
        if (!NewsRelType.homePage.equals(type)) {
            newsValidator.validateGetById(targetId);
        }
        Long newsId = news.getId();
        if (newsId != null) {// update
            infoNewsDao.update(news);
        } else {
            newsId = Long.valueOf(infoNewsDao.addNews(news));
			boolean aa = NewsRelType.homePage.equals(type) || NewsRelType.associate.equals(type);
			if (newsId != null && aa) {
                NewsUpdateEvent event = NewsUpdateEvent.produceInstance(Long.valueOf(newsId + ""));
                messageSender.sendModify(event);
            }
        }
        if (newsId != null) {
            this.addNewsInfoRel(targetId, type, newsId.intValue());
        }
        return newsId;

    }

    /**
     * 根据地区id列表和标的物类型分页查找新闻列表
     *
     * @param regionIds     *地区id列表
     * @param tickerType    *标的物类型
     * @param currentNewsId *分页的起始新闻id
     * @param pageSize      *分页大小
     * @return
     */
    @Override
    public List<News> searchByTickerType(Integer[] regionIds, Integer tickerType, Long currentNewsId, Integer pageSize,
                                         String lang) throws ApiException {
        newsValidator.validateSearchByTickerType(regionIds, tickerType, currentNewsId, pageSize, lang);
        return infoNewsDao.searchByTickerType(regionIds, tickerType, currentNewsId, pageSize, lang);
    }

    @Override
    public List<Integer> searchTickerTypeByNewsId(Long newsId) throws ApiException {
        newsValidator.validateGetByLongId(newsId);
        return infoNewsDao.searchTickerTypeByNewsId(newsId);
    }

    /**
     * 获取新闻，但不要详情
     */
    @Override
    public News getById(Long id) throws ApiException {
        return getById(id, false);
    }

    /**
     * 根据id查找对应的新闻
     *
     * @param id 新闻id
     * @return 对应的新闻对象，当为空时，返回null
     */
    @Override
    public News getById(Long id, Boolean detail) throws ApiException {
        newsValidator.validateGetByLongId(id);
        News news = infoNewsDao.getById(id);

        return news;
    }

    /**
     * 根据tickerId获取新闻信息列表
     *
     * @param tickerId
     * @param currentNewsId
     * @param pageSize
     * @return
     * @since 0.1.0
     */
    @Override
    public List<News> searchByTickerId(Integer tickerId, Long currentNewsId, Integer pageSize, String lang) {
        newsValidator.validateGetById(tickerId);
        newsValidator.validateStringError(lang);
        return infoNewsDao.searchByTickerId(tickerId, currentNewsId, pageSize, lang);
    }

    /**
     * service接口提供去重， 由于表数据存在重复，不使用DISTINCT去重， 排序后，用id去重
     */
    @Override
    public List<News> searchByTickerIds(Integer[] tickerIds, Long currentNewsId, Integer pageSize, String lang) {
        newsValidator.validateSearchByIds(tickerIds);
        List<News> result = new ArrayList<>();
        do {
            List<News> t = _searchByTickerIds(tickerIds, currentNewsId, pageSize, lang);
            if (t == null || t.isEmpty())
                return result;
            Long repeated = currentNewsId;
            for (int i = 0; i < t.size(); i++) {
                if (!t.get(i).getId().equals(repeated))
                    result.add(t.get(i));
                if (result.size() >= pageSize)
                    return result;
                repeated = t.get(i).getId();
            }
            currentNewsId = t.get(t.size() - 1).getId();
        } while (true);
    }

    private List<News> _searchByTickerIds(Integer[] tickerIds, Long currentNewsId, Integer pageSize, String lang) {
        return infoNewsDao.searchByTickerIds(tickerIds, currentNewsId, pageSize, lang);
    }

    /**
     * @param currentNewsId
     * @param pageSize
     * @param lang
     * @return
     * @throws ApiException
     */
    @Override
    public List<News> searchHomeNewsByLang(Long currentNewsId, Integer pageSize, String lang) throws ApiException {
        newsValidator.validateGetById(pageSize);
        return infoNewsDao.searchHomeNewsByLang(currentNewsId, pageSize, lang);
    }

    @Override
    @Deprecated
    public List<News> searchByRegionIds(String regionIds, Long currentNewsId, Integer pageSize, String lang) {
        return new ArrayList<>();
    }

    /**
     * 根据id查找新闻
     *
     * @param id 新闻id
     * @return 对应的新闻标签对象
     */
    @Override
    public List<NewsLabel> searchNewLablesById(Long id) {
        newsValidator.validateGetByLongId(id);
        return infoNewsDao.searchNewLablesById(id);
    }

    /**
     * 根据ids查找新闻标签
     *
     * @param ids 新闻id
     * @return 对应的新闻标签对象
     */
    @Override
    public Map<Long, List<NewsLabel>> searchNewLablesByIds(Long[] ids) {
        newsValidator.validateObjectNull(ids);
        List<NewsLabelExt> labels = infoNewsDao.searchNewLablesByIds(ids);
        Map<Long, List<NewsLabel>> result = new HashMap<>();
        for (int i = 0; labels != null && i < labels.size(); i++) {
            NewsLabelExt labelEx = labels.get(i);
            Long key = labelEx.getNewsId();
            NewsLabel label = new NewsLabel();
            BeanUtils.copyProperties(labelEx, label);
            if (!result.containsKey(key)) {
                List<NewsLabel> value = new ArrayList<NewsLabel>();
                value.add(label);
                result.put(key, value);
            } else {
                result.get(key).add(label);
            }
        }
        return result;
    }

    /**
     * 查询(管理新闻列表)
     */
    @Override
    public List<News> searchNewsByParm(NewsParam newsParam) throws ApiException {
        newsValidator.validateNewsParam(newsParam);
        return infoNewsDao.searchNewsByParm(newsParam);
    }

    /**
     * COUNT查询(管理新闻列表)
     */
    @Override
    public Integer countNewsByParm(NewsParam newsParam) throws ApiException {
        newsValidator.validateObjectNull(newsParam);
        return infoNewsDao.countNewsByParm(newsParam);
    }

    /**
     * 根据新闻ID删除
     *
     * @param id
     * @return
     * @since 0.1.0
     */
    @Override
    public void delById(Long id) throws ApiException {
        newsValidator.validateGetByLongId(id);
        infoNewsDao.delById(id);
    }

    /**
     * 更新新闻
     *
     * @return
     * @since 0.1.0
     */
    @Override
    public News update(News news) throws ApiException {
        newsValidator.validateUpdate(news);
        infoNewsDao.update(news);
        return news;
    }

    @Override
    public List<News> queryPaging(Long lastId, Integer pageSize) throws ApiException {
        newsValidator.validateGetById(pageSize);
        return infoNewsDao.queryPaging(Optional.ofNullable(lastId).orElse(-1l), pageSize);
    }

    /**
     * 根据新闻id查询关联的标的物
     *
     * @param id
     * @return
     * @throws ApiException
     * @date 2016年8月19日 上午11:35:22
     */
    @Override
    public List<Integer> getTickerIdByNewId(Integer id) throws ApiException {
        newsValidator.validateGetById(id);
        return infoNewsDao.getTickerIdByNewId(id);
    }

    @Override
    public List<Integer> searchCurrencyIdByNewId(Integer id) throws ApiException {
        newsValidator.validateGetById(id);
        return infoNewsDao.searchCurrencyIdByNewId(id);
    }

    @Override
    public List<Integer> searchFutrueGroupIdByNewId(Integer id) throws ApiException {
        newsValidator.validateGetById(id);
        return infoNewsDao.searchFutrueGroupIdByNewId(id);
    }

    /**
     * @param currencyId
     * @param currentNewsId
     * @param pageSize
     * @param lang
     * @return
     * @throws ApiException
     */
    @Override
    public List<News> searchByCurrencyIds(Integer[] currencyId, Long currentNewsId, Integer pageSize, String lang)
            throws ApiException {
        newsValidator.validateSearchByIds(currencyId);
        newsValidator.validateStringError(lang);
        return infoNewsDao.searchByCurrencyId(currencyId, currentNewsId, pageSize, lang);
    }

    @Override
    public List<News> searchByFuturesId(Integer groupsId, Long currentNewsId, Integer pageSize, String lang)
            throws ApiException {
        newsValidator.validateGetById(groupsId);
        newsValidator.validateGetById(pageSize);
        newsValidator.validateStringError(lang);
        return infoNewsDao.searchByFuturesId(groupsId, currentNewsId, pageSize, lang);
    }

    @Override
    public List<Integer> searchRelTickerIds(Long newsId) throws ApiException {
        newsValidator.validateGetByLongId(newsId);
        return infoNewsDao.searchRelTickerIds(newsId);
    }

    @Override
    public List<Integer> searchAssocNewsIds(Integer newsId) throws ApiException {
        newsValidator.validateGetById(newsId);
        return newsAssociateDao.searchAssocNewsIds(newsId);
    }

    @Override
    public String existLangChain_HomePage(List<String> langs) {
        newsValidator.validateIdsList(langs);
        for (String lang : langs) {
            if (Optional.ofNullable(infoNewsDao.langChainRegionScreen(lang)).filter(r0 -> r0 > 0).isPresent()) {
                return lang;
            }
        }
        return null;
    }

    @Override
    public String existLangChain_tickerIds(List<String> langs, List<Integer> tickerIds) {
        newsValidator.validateIdsList(tickerIds);
        newsValidator.validateIdsList(langs);
        for (String lang : langs) {
            if (Optional.ofNullable(infoNewsDao.langChainTickerScreen(tickerIds, lang)).filter(r0 -> r0 > 0)
                    .isPresent()) {
                return lang;
            }
        }
        return null;
    }

    @Override
    public String existLangChain_futrueIds(List<String> langs, Integer futrueId) {
        newsValidator.validateGetById(futrueId);
        newsValidator.validateIdsList(langs);
        for (String lang : langs) {
            if (Optional.ofNullable(infoNewsDao.langChainFutrueScreen(futrueId, lang)).filter(r0 -> r0 > 0)
                    .isPresent()) {
                return lang;
            }
        }
        return null;
    }

    @Override
    public String existLangChain_currencyIds(List<String> langs, List<Integer> currencyIds) {
        newsValidator.validateIdsList(currencyIds);
        newsValidator.validateIdsList(langs);
        for (String lang : langs) {
            if (Optional.ofNullable(infoNewsDao.langChainCurrencyScreen(currencyIds, lang)).filter(r0 -> r0 > 0)
                    .isPresent()) {
                return lang;
            }
        }
        return null;
    }

    @Override
    public String existLangChain_tickTypes(List<String> langs, Integer tickerType, List<Integer> regionIds) {
        newsValidator.validateIdsList(regionIds);
        newsValidator.validateIdsList(langs);
        newsValidator.validateObjectNull(tickerType);
        for (String lang : langs) {
            if (Optional.ofNullable(infoNewsDao.langChainTickerTypeScreen(regionIds, tickerType, lang))
                    .filter(r0 -> r0 > 0).isPresent()) {
                return lang;
            }
        }
        return null;
    }
}
